package qmlt.dataset.filter;

import java.util.ArrayList;
import java.util.List;

import qmlt.dataset.Attribute;
import qmlt.dataset.DataSetBase;
import qmlt.dataset.DataSet;
import qmlt.dataset.DataSetDef;
import qmlt.dataset.Instance;
import qmlt.dataset.utils.DataSetUtils;
import qmlt.dataset.utils.ListUtils;

public abstract class DiscretizingFilter implements Filter
{
	@Override
	public DataSet filter(DataSet ds)
	{
		assert (ds.getTargetDef().type.equals(Attribute.STRING)) : "discretizing filter can only operate on classification problems";

		List<Attribute> newFeatureDefs = new ArrayList<Attribute>();
		for (int i = 0; i < ds.getFeatureDefs().size(); ++i)
		{
			newFeatureDefs.add(new Attribute(Attribute.STRING, null));
		}
		DataSetDef newDef = new DataSetDef(ds.getId() + "-discrete", newFeatureDefs, ds.getTargetDef());
		DataSet newDs = new DataSetBase(newDef, ds);
		for (Instance inst : ds.getInstances())
		{
			inst.shallowClone(newDs);
		}

		for (int i = 0; i < ds.getFeatureDefs().size(); ++i)
		{
			if (ds.getFeatureDefs().get(i).type.equals(Attribute.FLOAT))
			{
				List<Float> values = ListUtils.convert(DataSetUtils.getFeatureColumn(ds.getInstances(), i));
				List<Object> classes = DataSetUtils.getTargetColumn(ds.getInstances());

				List<Float> div = getDividers(values, classes);

				for (int j = 0; j < newDs.getInstances().size(); ++j)
				{
					Instance inst = newDs.getInstances().get(j);
					float pre = (Float) inst.getFeatures().get(i);
					int discrete = discretize(pre, div);
					inst.getFeatures().set(i, String.valueOf(discrete));
				}
			}
		}

		return newDs;
	}

	public int discretize(float value, List<Float> dividers)
	{
		int i = 0;
		for (i = 0; i < dividers.size(); ++i)
		{
			if (value < dividers.get(i))
				break;
		}
		return i + 1;
	}

	public abstract List<Float> getDividers(List<Float> values, List<Object> classes);
}
